package com.lam.generator.controller;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.lam.common.base.controller.BaseController;
import com.lam.common.base.domain.Result;
import com.lam.common.components.dict.annotation.DictAutoTransfer;
import com.lam.common.components.file.FileDownloadUtil;
import com.lam.common.exception.BusinessException;
import com.lam.common.utils.DateUtil;
import com.lam.common.utils.ServletUtils;
import com.lam.common.utils.StringUtils;
import com.lam.common.validate.ValidateUtil;
import com.lam.common.validate.group.Update;
import com.lam.framework.annotation.ParamInject;
import com.lam.framework.operLog.annotation.Log;
import com.lam.framework.operLog.enums.BusinessType;
import com.lam.framework.operLog.enums.LogSave;
import com.lam.generator.common.constant.GeneratorConstant;
import com.lam.generator.common.util.GenUtils;
import com.lam.generator.entity.DbTable;
import com.lam.generator.entity.GenTable;
import com.lam.generator.param.GenDbTableParam;
import com.lam.generator.param.GenTableParam;
import com.lam.generator.service.GenDbTableService;
import com.lam.generator.service.GenTableService;

/**
 * 代码生成 操作处理
 */
@Log(title = "代码生成")
@RestController
@ParamInject
@RequestMapping("/${adminPath}/tool/gen")
public class GenController extends BaseController {
	
	@Autowired
	private GenTableService genTableService;
	@Autowired
	private GenDbTableService genDbTableService;

	/**
	 * 查询数据库列表
	 */
	@Log(oper="分页查询数据库表")
	@PreAuthorize("@ss.hasPm('tool:gen:list')")
	@GetMapping("/db/list")
	public Result dbList(GenDbTableParam param) {
		
		startPage();
		param.setFilterImport(true);
		List<DbTable> list = genDbTableService.selectTableList(param);
		return Result.ok(getTableData(list));
	}
	
	/**
	 * 查询代码生成列表
	 */
	@DictAutoTransfer
	@Log(oper="分页查询")
	@PreAuthorize("@ss.hasPm('tool:gen:list')")
	@GetMapping("/list")
	public Result list(GenTableParam param) {
		
		startPage();
		List<GenTable> list = genTableService.selectList(param);
		return Result.ok(getTableData(list));
	}

	/**
	 * 根据ID查询
	 */
	@Log(oper="根据ID查询")
	@PreAuthorize("@ss.hasPm('tool:gen:query')")
	@GetMapping("/{tableId}")
	public Result getInfo(@PathVariable String tableId) {
		
		ValidateUtil.validRequired(tableId, "表id不能为空！");
		
		return Result.ok(genTableService.selectById(tableId));
	}

	/**
	 * 从数据库同步表结构
	 */
	@PreAuthorize("@ss.hasPm('tool:gen:syncFromDb')")
	@Log(oper = "从数据库同步表结构", businessType = BusinessType.UPDATE)
	@PostMapping("/syncFromDb/{tableId}")
	public Result syncFromDb(@PathVariable String tableId) {
		
		ValidateUtil.validRequired(tableId, "表id不能为空！");
		
		genTableService.syncFromDb(tableId);
		return Result.ok();
	}
	
	/**
	 * 检查类是否可用
	 */
	@PreAuthorize("@ss.hasPm('tool:gen:checkClass')")
	@Log(oper = "检查类是否可用", businessType = BusinessType.QUERY, logSave = LogSave.YES)
	@PostMapping("/checkClass")
	public Result checkClass(@RequestBody GenTableParam param) {
		
		ValidateUtil.validRequired(param.getClassName(), "类名不能为空！");
		
		return GenUtils.loadClass(param.getClassName())!=null ? Result.ok() : Result.fail("未找到该类文件！");
	}

	/**
	 * 导入表结构（保存）
	 */
	@PreAuthorize("@ss.hasPm('tool:gen:importTable')")
	@Log(oper = "导入表生成代码配置", businessType = BusinessType.INSERT)
	@PostMapping("/importTable")
	public Result importTableSave(@RequestBody GenTableParam param) {
		
		ValidateUtil.validRequired(param.getTableName(), "表名不能为空！");
		
		genTableService.importGenTable(param.getTableName());
		return Result.ok();
	}

	/**
	 * 修改代码生成配置
	 */
	@PreAuthorize("@ss.hasPm('tool:gen:edit')")
	@Log(oper = "修改代码生成配置", businessType = BusinessType.UPDATE, logSave = LogSave.NO)
	@PutMapping
	public Result edit(@Validated(Update.class) @RequestBody GenTable genTable) {
		
		if (GeneratorConstant.TEMP_TYPE_SIMPLE_TREE.equals(genTable.getTemplateType())) {
			ValidateUtil.validRequired(genTable.getOptionObject(), GeneratorConstant.TREE_CODE, "树编码字段不能为空");
			ValidateUtil.validRequired(genTable.getOptionObject(), GeneratorConstant.TREE_PARENT_CODE, "树父编码字段不能为空");
		}
		
		if(StringUtils.isNotBlank(genTable.getParentClassName()) && GenUtils.loadClass(genTable.getParentClassName()) == null) {
			return Result.fail("未找到实体类父类文件！");
		}
		
		genTableService.update(genTable);
		return Result.ok();
	}

	/**
	 * 删除代码生成配置
	 */
	@PreAuthorize("@ss.hasPm('tool:gen:remove')")
	@Log(oper = "删除代码生成配置", businessType = BusinessType.DELETE)
	@DeleteMapping("/{tableIds}")
	public Result delete(@PathVariable String tableIds) {
		
		ValidateUtil.validRequired(tableIds, "表id不能为空！");
		
		genTableService.deleteById(tableIds);
		return Result.ok();
	}

	/**
	 * 预览代码
	 */
	@Log(oper = "预览代码", businessType = BusinessType.OTHER)
	@PreAuthorize("@ss.hasPm('tool:gen:preview')")
	@GetMapping("/preview/{tableId}")
	public Result preview(@PathVariable("tableId") String tableId) {
		
		ValidateUtil.validRequired(tableId, "表id不能为空！");
		
		Map<String, String> dataMap = genTableService.previewCode(tableId);
		return Result.ok(dataMap);
	}

	/**
	 * 生成代码到项目（自定义路径）
	 */
	@PreAuthorize("@ss.hasPm('tool:gen:genCode')")
	@Log(oper = "生成代码到项目", businessType = BusinessType.OTHER, logSave = LogSave.YES)
	@GetMapping("/genCode/{tableId}")
	public Result genCode(HttpServletResponse response, @PathVariable("tableId") String tableId) {
		
		ValidateUtil.validRequired(tableId, "表id不能为空！");
		
		genTableService.generatorCode2Project(tableId);
		return Result.ok();
	}
	
	/**
	 * 批量表生成代码
	 */
	@PreAuthorize("@ss.hasPm('tool:gen:batchGenCode')")
	@Log(oper = "批量表生成代码", businessType = BusinessType.DOWNLOAD)
	@GetMapping("/batchGenCode")
	public void batchGenCode(HttpServletResponse response, String tableIds, String s) {
		
		try {
			ValidateUtil.validRequired(tableIds, "表id不能为空！");
			outWrite(response, genTableService.downloadCode(tableIds));
		} catch (Exception e) {
			FileDownloadUtil.writeFail(ServletUtils.getResponse(), e, s);
		}
	}

	/**
	 * 生成zip文件
	 */
	private void outWrite(HttpServletResponse response, byte[] data) {
		try {
			response.reset();
			response.addHeader("Access-Control-Allow-Origin", "*");
			response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
			response.setHeader("Content-Disposition", "attachment; filename=\"lam_code_gen__"+DateUtil.getDate(DateUtil.PATTERN_YYYYMMDDHHMMSS_SSS)+".zip\"");
			response.addHeader("Content-Length", "" + data.length);
			response.setContentType("application/octet-stream; charset=UTF-8");
			IOUtils.write(data, response.getOutputStream());
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new BusinessException("生成代码失败");
		}
	}
}